package com.tymoshenko.seabattle.shared.model.domain;

import java.io.Serializable;
import java.util.*;

/**
 * Used only for initial ships placement
 *
 * @author Yakiv Tymoshenko
 * @since 21.01.13
 */
public class Ship implements Serializable {

    public static enum Type {
        FOUR_DECK(4), THREE_DECK(3), TWO_DECK(2), ONE_DECK(1);

        private int decks;

        Type(int decks) {
            this.decks = decks;
        }

        public int getDecks() {
            return decks;
        }
    }

    public static enum Direction {
        HORIZONTAL, VERTICAL
    }

    private static Map<Type, Integer> placementRules;

    static {
        placementRules = new EnumMap<Type, Integer>(Type.class);
        placementRules.put(Type.FOUR_DECK, 1);
        placementRules.put(Type.THREE_DECK, 2);
        placementRules.put(Type.TWO_DECK, 3);
        placementRules.put(Type.ONE_DECK, 4);
    }

    public static Map<Type, Integer> getPlacementRules() {
        return Collections.unmodifiableMap(placementRules);
    }

    private Type type;
    private Direction direction;
    private Point firstDeck;
    private Point lastDeck;
    private List<Point> decks;

    @SuppressWarnings("unused")
    private Ship() {
    }

    public Ship(Type type, Direction direction, Point firstDeck) {
        this.type = type;
        this.direction = direction;
        this.firstDeck = firstDeck;
        initDecks();
    }

    public Type getType() {
        return type;
    }

    public Direction getDirection() {
        return direction;
    }

    public Point getFirstDeck() {
        return firstDeck;
    }

    public Point getLastDeck() {
        return lastDeck;
    }

    public List<Point> getDecks() {
        return Collections.unmodifiableList(decks);
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(getType().toString());
        sb.append(" ");
        if (type != Type.ONE_DECK) {
            sb.append(getDirection());
            sb.append(" Decks: ");
            for (Point deck : decks) {
                sb.append(deck);
                sb.append(" ");
            }
        } else {
            sb.append(decks.get(0));
        }
        sb.append(". ");
        return sb.toString();
    }

    private void initDecks() {
        List<Point> decks = new ArrayList<Point>(4);
        for (int i = 0; i < type.getDecks(); i++) {
            if (direction == Ship.Direction.VERTICAL) {
                // (1, 1) -> (2, 1)
                decks.add(Point.valueOf(firstDeck.getRow() + i, firstDeck.getCol()));
            } else {
                // (1, 1) -> (1, 2)
                decks.add(Point.valueOf(firstDeck.getRow(), firstDeck.getCol() + i));
            }
        }
        this.decks = decks;
        this.lastDeck = decks.get(decks.size() - 1);
    }
}
